// demo1_bunny.c

#include "demo1_bunny.h" // 引入 demo1_bunny.h，它会引入所有依赖项

// 全局实例，以便任务函数可以访问，从 main.c 迁移过来，现在作为参数传递
// VdmaDisplay g_vdma_display; // 不再在这里定义，而是从 main 传入
// SmrsContext g_smrs_context; // 不再在这里定义，而是从 main 传入

// --- 全局存储渲染三角形数据，避免任务栈溢出 ---
// 这个数组用于存储当前帧要渲染的所有三角形，从任务栈移至全局静态内存。
SmrsTriangle render_triangles_global[BUNNY_NUM_TRIANGLES];

// 动画变量
// (1) 兔子不再自转，保持静止。设置一个初始旋转角度。
float rotation_angle_y = M_PI; // 兔子初始绕Y轴旋转180度，使其模型正面朝向默认摄像机
// (2) 摄像机改为动态的，围绕兔子转动
float camera_orbit_angle = 0.0f; // 摄像机绕Y轴旋转的角度

// 渲染任务参数结构体
typedef struct {
    VdmaDisplay* vdma_display;
    SmrsContext* smrs_context;
    QueueHandle_t hdmi_ready_queue; // 依然需要队列来接收信号
} GpuRenderTaskParams_t;


// --- GPU 渲染任务实现 ---
void vGpuRenderTask( void *pvParameters )
{
    GpuRenderTaskParams_t* params = (GpuRenderTaskParams_t*)pvParameters;
    VdmaDisplay* g_vdma_display = params->vdma_display;
    SmrsContext* g_smrs_context = params->smrs_context;
    QueueHandle_t xHdmiReadyQueue = params->hdmi_ready_queue;

    int received_signal = 0;

    // FreeRTOS Tick Rate (ticks per second)
    const float ticks_to_ms_factor = 1000.0f / (float)configTICK_RATE_HZ;
    
    // 等待 HDMI 初始化任务完成信号
    xil_printf("[GPU Render Task]: Waiting for HDMI Init completion signal...\r\n");
    if (xQueueReceive( xHdmiReadyQueue, &received_signal, portMAX_DELAY ) != pdPASS) {
        xil_printf("[GPU Render Task]: FATAL ERROR: Failed to receive HDMI ready signal from queue. Task cannot proceed.\r\n");
        for( ;; ) { vTaskDelay( portMAX_DELAY ); }
    }
    xil_printf("[GPU Render Task]: HDMI Init completed. Starting GPU rendering loop.\r\n");
    
    u32 hls_render_width = VdmaDisplay_getHlsRenderWidth(g_vdma_display);   // HLS 渲染宽度 (320)
    u32 hls_render_height = VdmaDisplay_getHlsRenderHeight(g_vdma_display); // HLS 渲染高度 (240)


    // --- 3D 渲染设置 ---
    float fov_y_rad = 60.0f * M_PI / 180.0f; // 60 度视角
    // 调整纵横比，以 HLS 渲染分辨率为准
    float aspect_ratio = (float)hls_render_width / (float)hls_render_height;
    float near_plane = 0.1f;
    float far_plane = 100.0f; // 调整 far_plane 以匹配 GPU_Render_Test.cpp 的设置
    
    Matrix4 projection_matrix = Mat4_perspective(fov_y_rad, aspect_ratio, near_plane, far_plane);
    
    // 光源改为世界空间中
    // 定义光的入射方向 (从光源到物体表面) - 世界空间
    Vector3 L_world = Vec3_normalize((Vector3){1.0f, 1.0f, 1.0f}); // 从世界空间右上方前方照来
    
    // 光源颜色 (白色光)
    Vector3 light_color = {1.0f, 1.0f, 1.0f}; // R, G, B (0.0 to 1.0)
    
    // 材质属性 (Phong Model)
    Vector3 material_ambient = {0.4f, 0.4f, 0.4f};   // 环境光反射系数
    Vector3 material_diffuse = {0.7f, 0.7f, 0.7f};   // 漫反射反射系数
    Vector3 material_specular = {0.9f, 0.9f, 0.9f};  // 镜面反射反射系数 (高光颜色)
    float shininess = 32.0f;                        // 镜面反射高光强度 (越大越亮越集中)
    
    // 物体基础颜色 (兔子模型的基色，这里使用淡黄色，将其转换为0-1范围)
    Vector3 object_base_color = {255.0f/255.0f, 255.0f/255.0f, 150.0f/255.0f};
    
    // --- 渲染循环 ---
    const u32 FPS_MEASUREMENT_INTERVAL_FRAMES = 10; // 每10帧测量一次FPS
    TickType_t fps_last_measurement_start_ticks = xTaskGetTickCount();
    u32 frames_since_last_measurement = 0;
    float current_fps = 0.0f;
    
    #define FLOAT_STR_BUFFER_SIZE 64 

    // 用于 snprintf 浮点数的缓冲区
    char text_print_buffer_fps[FLOAT_STR_BUFFER_SIZE];
    char text_print_buffer_tris[FLOAT_STR_BUFFER_SIZE];
    
    // 摄像机动态参数
    const float CAMERA_ORBIT_RADIUS = 5.0f; // 摄像机围绕兔子的半径
    const float CAMERA_ORBIT_HEIGHT = 1.0f; // 摄像机的高度
    const float CAMERA_ORBIT_SPEED = 0.02f; // 摄像机旋转速度 (弧度/帧)
    
    while( 1 )
    {
        // --- 同步：等待一个可用的渲染缓冲区 ---
        // 注意：这部分等待时间不计入渲染管线性能。
        if (xSemaphoreTake(g_vdma_display->xRenderingBufferAvailableSemaphore_, portMAX_DELAY) != pdPASS) {
            xil_printf("[GPU Render Task]: FATAL ERROR: Failed to take xRenderingBufferAvailableSemaphore_.\r\n");
            for( ;; ) { vTaskDelay( portMAX_DELAY ); }
        }
        
        // 1. 获取当前要渲染到的 HLS 帧缓冲区地址和索引
        int current_render_fb_idx = VdmaDisplay_getNextHlsWriteBufferIdx(g_vdma_display);
        UINTPTR hls_framebuffer_addr = VdmaDisplay_getHlsFrameBufferAddr(g_vdma_display, current_render_fb_idx);
        UINTPTR vdma_framebuffer_addr = VdmaDisplay_getVdmaFrameBufferAddr(g_vdma_display, current_render_fb_idx); // 获取对应的 VDMA 就绪缓冲区地址
    
        if (hls_framebuffer_addr == 0 || vdma_framebuffer_addr == 0) {
            xil_printf("[GPU Render Task]: ERROR: Failed to get valid HLS/VDMA framebuffer address for index %d. Retrying.\r\n", current_render_fb_idx);
            // 出现错误时，需要释放信号量，否则会造成死锁
            xSemaphoreGive(g_vdma_display->xRenderingBufferAvailableSemaphore_);
            vTaskDelay( pdMS_TO_TICKS(10) );
            continue;
        }
    
        // 2. 清空帧缓冲区和 ZBuffer (由 SMRS 模块处理)
        if (Smrs_ClearFrameAndZBuffer(g_smrs_context, hls_framebuffer_addr) != SMRS_SUCCESS) {
            xil_printf("[GPU Render Task]: ERROR: Smrs_ClearFrameAndZBuffer failed.\r\n");
            xSemaphoreGive(g_vdma_display->xRenderingBufferAvailableSemaphore_);
            vTaskDelay( pdMS_TO_TICKS(10) );
            continue;
        }
    
        // --- 更新动画数据 (摄像机围绕兔子旋转) ---
        // 兔子保持静止，不更新 rotation_angle_y
        
        // 摄像机围绕兔子转动
        camera_orbit_angle += CAMERA_ORBIT_SPEED;
        if (camera_orbit_angle >= 2.0f * M_PI) camera_orbit_angle -= 2.0f * M_PI;
    
        // --- 设置模型、视图矩阵 ---
        Matrix4 model_matrix = Mat4_identity();
        model_matrix = Mat4_multiply(Mat4_scale(3.0f, 3.0f, 3.0f), model_matrix);             // 1. 缩放
        model_matrix = Mat4_multiply(Mat4_rotateY(rotation_angle_y), model_matrix);           // 2. 旋转
        model_matrix = Mat4_multiply(Mat4_translate(0.0f, 0.0f, 0.0f), model_matrix);         // 3. 平移 (兔子模型稍微下移)
    
        // 摄像机目标点 (看向兔子中心)
        Vector3 camera_target_world = {0.0f, 0.5f, 0.0f}; // 摄像机看向兔子中心
    
        // 摄像机位置 (动态围绕兔子转动)
        Vector3 camera_pos_world;
        camera_pos_world.x = camera_target_world.x + CAMERA_ORBIT_RADIUS * sinf(camera_orbit_angle);
        camera_pos_world.y = CAMERA_ORBIT_HEIGHT; // 保持摄像机高度不变
        camera_pos_world.z = camera_target_world.z + CAMERA_ORBIT_RADIUS * cosf(camera_orbit_angle);
        
        Vector3 camera_up_world = {0.0f, 1.0f, 0.0f}; // 世界Y轴是向上
    
        Matrix4 view_matrix = Mat4_lookAt(camera_pos_world, camera_target_world, camera_up_world);
    
        Matrix4 mvp_matrix = Mat4_multiply(projection_matrix, Mat4_multiply(view_matrix, model_matrix));
    
        // --- 渲染兔子模型，并将处理后的三角形存储到 `render_triangles_global` ---
        u32 total_valid_triangles_in_frame = 0;
    
        for (u32 i = 0; i < BUNNY_NUM_TRIANGLES; ++i) {
            // 获取原始顶点和法线
            Vector3 v0_model = {bunny_vertices[bunny_indices[i][0]][0], bunny_vertices[bunny_indices[i][0]][1], bunny_vertices[bunny_indices[i][0]][2]};
            Vector3 v1_model = {bunny_vertices[bunny_indices[i][1]][0], bunny_vertices[bunny_indices[i][1]][1], bunny_vertices[bunny_indices[i][1]][2]};
            Vector3 v2_model = {bunny_vertices[bunny_indices[i][2]][0], bunny_vertices[bunny_indices[i][2]][1], bunny_vertices[bunny_indices[i][2]][2]};
    
            Vector3 n0_model = {bunny_normals[bunny_indices[i][0]][0], bunny_normals[bunny_indices[i][0]][1], bunny_normals[bunny_indices[i][0]][2]};
            // 对于平坦着色，我们只用一个顶点法线作为面法线
            Vector3 face_normal_model = Vec3_normalize(n0_model); 
    
            // 1. 变换顶点到裁剪空间 (Clip Space)
            Vector4_f v0_hom = {v0_model.x, v0_model.y, v0_model.z, 1.0f};
            Vector4_f v1_hom = {v1_model.x, v1_model.y, v1_model.z, 1.0f};
            Vector4_f v2_hom = {v2_model.x, v2_model.y, v2_model.z, 1.0f};
    
            // 应用 MVP 矩阵
            Vector4_f v0_clip_hom = Mat4_mul_Vec4(mvp_matrix, v0_hom);
            Vector4_f v1_clip_hom = Mat4_mul_Vec4(mvp_matrix, v1_hom);
            Vector4_f v2_clip_hom = Mat4_mul_Vec4(mvp_matrix, v2_hom);
    
            // 简单的背面剔除 (在裁剪空间进行)
            // (v1-v0) x (v2-v0) 的 Z 分量符号判断顺逆时针
            float cross_product_z_clip = (v1_clip_hom.x - v0_clip_hom.x) * (v2_clip_hom.y - v0_clip_hom.y) - 
                                         (v1_clip_hom.y - v0_clip_hom.y) * (v2_clip_hom.x - v0_clip_hom.x);
            
            // 如果 cross_product_z_clip < 0.0f，表示顺时针，是背面。剔除。
            if (cross_product_z_clip < 0.0f) {
                continue; // 剔除背面三角形
            }
    
            // --- W 裁剪和透视除法得到 NDC 坐标 ---
            // 确保 w 不为 0，防止除零。同时作为简单近裁剪。
            if (v0_clip_hom.w <= 0.001f || v1_clip_hom.w <= 0.001f || v2_clip_hom.w <= 0.001f) continue;
            
            // 透视除法得到 NDC 坐标
            Vector3 v0_ndc = {v0_clip_hom.x / v0_clip_hom.w, v0_clip_hom.y / v0_clip_hom.w, v0_clip_hom.z / v0_clip_hom.w};
            Vector3 v1_ndc = {v1_clip_hom.x / v1_clip_hom.w, v1_clip_hom.y / v1_clip_hom.w, v1_clip_hom.z / v1_clip_hom.w};
            Vector3 v2_ndc = {v2_clip_hom.x / v2_clip_hom.w, v2_clip_hom.y / v2_clip_hom.w, v2_clip_hom.z / v2_clip_hom.w};
    
            // 再次进行粗略的裁剪，检查 NDC 范围
            // 如果所有顶点都完全在 NDC 盒外，则跳过
            u8 out_count = 0;
            if (v0_ndc.x < -1.0f || v0_ndc.x > 1.0f || v0_ndc.y < -1.0f || v0_ndc.y > 1.0f || v0_ndc.z < -1.0f || v0_ndc.z > 1.0f) out_count++;
            if (v1_ndc.x < -1.0f || v1_ndc.x > 1.0f || v1_ndc.y < -1.0f || v1_ndc.y > 1.0f || v1_ndc.z < -1.0f || v1_ndc.z > 1.0f) out_count++;
            if (v2_ndc.x < -1.0f || v2_ndc.x > 1.0f || v2_ndc.y < -1.0f || v2_ndc.y > 1.0f || v2_ndc.z < -1.0f || v2_ndc.z > 1.0f) out_count++;
            if (out_count == 3) continue; // 所有顶点都在 NDC 盒外
    
            // 视口变换到屏幕坐标
            // 此时屏幕坐标是 HLS 渲染分辨率
            float screen_x_scale = (float)hls_render_width / 2.0f;
            float screen_y_scale = (float)hls_render_height / 2.0f;
    
            // X [-1, 1] -> [0, HLS_RENDER_WIDTH]
            // Y [-1, 1] -> [0, HLS_RENDER_HEIGHT] (Y 轴反转，因为屏幕坐标系Y轴向下)
            // Z [-1, 1] -> [0, 1] (归一化 Z)
            float scr_v0x = (v0_ndc.x + 1.0f) * screen_x_scale;
            float scr_v0y = (1.0f - v0_ndc.y) * screen_y_scale; // Y 轴反转，因为屏幕坐标Y向下
            float scr_v0z_norm = (v0_ndc.z + 1.0f) / 2.0f; // Z 归一化到 [0, 1]
    
            float scr_v1x = (v1_ndc.x + 1.0f) * screen_x_scale;
            float scr_v1y = (1.0f - v1_ndc.y) * screen_y_scale;
            float scr_v1z_norm = (v1_ndc.z + 1.0f) / 2.0f;
    
            float scr_v2x = (v2_ndc.x + 1.0f) * screen_x_scale;
            float scr_v2y = (1.0f - v2_ndc.y) * screen_y_scale;
            float scr_v2z_norm = (v2_ndc.z + 1.0f) / 2.0f;
    
            // --- 4. 设置三角形颜色 (Phong 光照模型) ---
            
            // 将法线从模型空间转换到世界空间，再到相机空间
            // 注意：仅旋转法线，不包含平移分量，所以使用Mat4_mul_Vec3_NoDiv_Direction
            Vector3 N_cam = Mat4_mul_Vec3_NoDiv_Direction(view_matrix, Mat4_mul_Vec3_NoDiv_Direction(model_matrix, face_normal_model));
            N_cam = Vec3_normalize(N_cam);
    
            // 将世界空间的光源方向 L_world 转换到相机空间 L_cam
            Vector3 L_cam = Mat4_mul_Vec3_NoDiv_Direction(view_matrix, L_world);
            L_cam = Vec3_normalize(L_cam); // 确保是单位向量
            
            // --- 视图向量 V_cam 的计算 ---
            // 1. 将模型空间顶点 v0_model (代表三角形表面点) 变换到世界空间
            Vector3 surface_pos_world = Mat4_mul_Vec3_Position(model_matrix, v0_model); 
    
            // 2. 计算世界空间中的视图向量 (从表面点指向相机位置)
            Vector3 V_world = Vec3_normalize(Vec3_sub(camera_pos_world, surface_pos_world));
    
            // 3. 将世界空间视图向量转换到相机空间
            //    注意：视图向量是方向，不应受平移影响，因此使用 Mat4_mul_Vec3_NoDiv_Direction
            Vector3 V_cam = Mat4_mul_Vec3_NoDiv_Direction(view_matrix, V_world);
            V_cam = Vec3_normalize(V_cam); // 确保是单位向量
    
            // 环境光 (Ambient)
            Vector3 ambient_color_term = Vec3_multiply_elements(material_ambient, light_color); // Ka * LightColor
    
            // 漫反射 (Diffuse)
            float diff_factor = fmaxf(0.0f, Vec3_dot(N_cam, L_cam)); // N . L
            Vector3 diffuse_color_term = Vec3_mul_scalar(Vec3_multiply_elements(material_diffuse, object_base_color), diff_factor);
            // 漫反射也受光源颜色影响 
            diffuse_color_term = Vec3_multiply_elements(diffuse_color_term, light_color);
    
            // 镜面反射 (Specular)
            Vector3 R_cam = Vec3_normalize(Vec3_sub(Vec3_mul_scalar(N_cam, 2.0f * Vec3_dot(N_cam, L_cam)), L_cam)); // R = 2 * (N.L) * N - L
            float spec_factor = fmaxf(0.0f, Vec3_dot(R_cam, V_cam));
            spec_factor = powf(spec_factor, shininess); // (R.V)^shininess
            Vector3 specular_color_term = Vec3_mul_scalar(Vec3_multiply_elements(material_specular, light_color), spec_factor); // Ks * LightColor * (R.V)^shininess


            // 最终颜色 = 环境光 + 漫反射 + 镜面反射
            Vector3 final_color_linear = Vec3_add(ambient_color_term, Vec3_add(diffuse_color_term, specular_color_term));
    
            // 将颜色分量钳制到 [0, 1] 范围，然后乘以 255
            SmrsTriangle* current_tri = &render_triangles_global[total_valid_triangles_in_frame];
            current_tri->r_f = fminf(fmaxf(final_color_linear.x, 0.0f), 1.0f) * 255.0f;
            current_tri->g_f = fminf(fmaxf(final_color_linear.y, 0.0f), 1.0f) * 255.0f;
            current_tri->b_f = fminf(fmaxf(final_color_linear.z, 0.0f), 1.0f) * 255.0f;
    
            // 5. 填充 SmrsTriangle 结构
            // 使用全局的 render_triangles_global 数组
            current_tri->v0x=scr_v0x; current_tri->v0y=scr_v0y; current_tri->v0z_norm=scr_v0z_norm;
            current_tri->v1x=scr_v1x; current_tri->v1y=scr_v1y; current_tri->v1z_norm=scr_v1z_norm;
            current_tri->v2x=scr_v2x; current_tri->v2y=scr_v2y; current_tri->v2z_norm=scr_v2z_norm;
    
            Smrs_CalculateEdgeEquations(current_tri->v0x, current_tri->v0y, current_tri->v1x, current_tri->v1y, current_tri->v2x, current_tri->v2y,
                &current_tri->edge0_A, &current_tri->edge0_B, &current_tri->edge0_C,
                &current_tri->edge1_A, &current_tri->edge1_B, &current_tri->edge1_C,
                &current_tri->edge2_A, &current_tri->edge2_B, &current_tri->edge2_C);
            
            // 注意：HLS IP 中的 ZBuffer 范围是 [0, 65535]，0为最近，65535为最远。
            // 但我们的归一化 Z 是 [0, 1]，0为近，1为远。
            // 因此，将 `v0z_norm` 反向映射，即 `(1.0f - v0z_norm) * 65535.0f` 传递给 Smrs_CalculateDepthGradients。
            Smrs_CalculateDepthGradients(current_tri->v0x, current_tri->v0y, (1.0f - current_tri->v0z_norm) * 65535.0f, 
                                            current_tri->v1x, current_tri->v1y, (1.0f - current_tri->v1z_norm) * 65535.0f, 
                                            current_tri->v2x, current_tri->v2y, (1.0f - current_tri->v2z_norm) * 65535.0f,
                                            &current_tri->dzdx, &current_tri->dzdy);
            
            total_valid_triangles_in_frame++;
            if (total_valid_triangles_in_frame >= BUNNY_NUM_TRIANGLES) {
                break; 
            }
        } // End of triangle processing loop
    
        // 6. 调度 SMRS 模块进行渲染
        if (Smrs_RenderTriangles(g_smrs_context, render_triangles_global, total_valid_triangles_in_frame, hls_framebuffer_addr) != SMRS_SUCCESS) {
            xil_printf("[GPU Render Task]: ERROR: Smrs_RenderTriangles failed.\r\n");
            xSemaphoreGive(g_vdma_display->xRenderingBufferAvailableSemaphore_);
            vTaskDelay( pdMS_TO_TICKS(10) );
            continue;
        }
        
        // ====================================================================================
        // 调用 VdmaDisplay_processAndConvertFrame 执行 PS 缩放 + 格式转换 + 对应缓存刷新
        // 这部分现在包含在 FPS 测量时间内。
        // ====================================================================================
        int status_convert = VdmaDisplay_processAndConvertFrame(g_vdma_display, current_render_fb_idx);
        if (status_convert != XST_SUCCESS) {
            xil_printf("[GPU Render Task]: ERROR: VdmaDisplay_processAndConvertFrame failed with status %d for buffer %d.\r\n", status_convert, current_render_fb_idx);
            // 错误处理策略可能需要更复杂的设计。当前就让它尝试显示损坏的帧。
        }

        // --- 结束测量当前帧的渲染时间 ---
        TickType_t frame_end_ticks = xTaskGetTickCount(); 
    
        // --- 计算 FPS ---
        frames_since_last_measurement++;
        if (frames_since_last_measurement >= FPS_MEASUREMENT_INTERVAL_FRAMES) {
            TickType_t elapsed_ticks = frame_end_ticks - fps_last_measurement_start_ticks;

            if (elapsed_ticks == 0) {
                current_fps = (float)configTICK_RATE_HZ; // 至少一个tick
            } else {
                float total_elapsed_ms = (float)elapsed_ticks * ticks_to_ms_factor;
                current_fps = (float)frames_since_last_measurement * 1000.0f / total_elapsed_ms;
            }
            fps_last_measurement_start_ticks = frame_end_ticks; // 更新为当前测量周期结束的时间
            frames_since_last_measurement = 0;
        }

        // --- 格式化 FPS 和三角形数量字符串 ---
        snprintf(text_print_buffer_fps, FLOAT_STR_BUFFER_SIZE, "FPS: %d", (int)roundf(current_fps));
        snprintf(text_print_buffer_tris, FLOAT_STR_BUFFER_SIZE, "Tris: %lu", (unsigned long)total_valid_triangles_in_frame);

        // 在 PS 缩放 + 格式转换完成后，提交给 VDMA 显示之前，在 VDMA-ready 缓冲区上绘制文本
        // 字体绘制应该作用在刚刚完成渲染和转换的 VDMA-ready 缓冲区上
        // 这个缓冲区的索引就是 current_render_fb_idx
        int target_vdma_buffer_idx = current_render_fb_idx; 

        // 绘制 FPS 字符串
        VdmaDisplay_DrawString(g_vdma_display, target_vdma_buffer_idx, 10, 10, text_print_buffer_fps, 255, 255, 255); // 白色文字 "FPS: XX"
        // 绘制三角形数量字符串
        // 文本绘制时，需要知道每个字符的字高，这里使用 VdmaDisplay_getFontHeight()
        VdmaDisplay_DrawString(g_vdma_display, target_vdma_buffer_idx, 10, 10 + VdmaDisplay_getFontHeight(g_vdma_display) + 10, text_print_buffer_tris, 255, 255, 255); // 白色文字 "Tris: XX", 间隔10像素

        // 调用 VdmaDisplay_presentFrameToVDMA 将帧提交给 VDMA 显示
        // 这部分不计入帧率测量时间。
        int status_present = VdmaDisplay_presentFrameToVDMA(g_vdma_display, current_render_fb_idx);
        if (status_present != XST_SUCCESS) {
            xil_printf("[GPU Render Task]: ERROR: VdmaDisplay_presentFrameToVDMA failed with status %d for buffer %d.\r\n", status_present, current_render_fb_idx);
        }
    }
}
